package com.wg.core.event;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.wg.core.controller.IController;

import java.lang.reflect.Method;

/**
 * 事件方法
 *
 * @author 少爷123
 */
public class EventMethod {
    private static final Log log = LogFactory.get();

    private final IController targetInstance;
    private final Method targetMethod;
    private final boolean asyncExecution;

    public EventMethod(IController targetInstance, Method targetMethod, boolean asyncExecution) {
        if (targetInstance == null) {
            throw new IllegalArgumentException("Target controller instance cannot be null");
        }
        if (targetMethod == null) {
            throw new IllegalArgumentException("Target method cannot be null");
        }

        this.targetInstance = targetInstance;
        this.targetMethod = targetMethod;
        this.asyncExecution = asyncExecution;

        ReflectUtil.setAccessible(targetMethod);
    }

    public IController getTargetInstance() {
        return targetInstance;
    }

    public void invoke(Event event) {
        if (event == null) {
            log.warn("Attempted to invoke event handler with null event");
            return;
        }

        if (asyncExecution) {
            submitAsyncTask(event);
        } else {
            executeInvocation(event);
        }
    }

    private void submitAsyncTask(Event event) {
        try {
            targetInstance.getFiber().enqueue(() -> {
                executeInvocation(event);
            });
        } catch (Exception e) {
            log.error("Failed to submit async event task [Method: {}, Event: {}]",
                    targetMethod.getName(), event, e);
        }
    }

    private void executeInvocation(Event event) {
        try {
            log.debug("Executing event handler [Class: {}, Method: {}, EventID: {}]",
                    targetInstance.getClass().getSimpleName(),
                    targetMethod.getName(),
                    event.getEventId());

            ReflectUtil.invoke(targetInstance, targetMethod, event);
        } catch (IllegalArgumentException e) {
            log.error("Argument mismatch in event handler [Class: {}, Method: {}, EventType: {}]",
                    targetInstance.getClass().getSimpleName(),
                    targetMethod.getName(),
                    event.getClass().getSimpleName(), e);
        } catch (Exception e) {
            log.error("Unexpected error in event handler [Class: {}, Method: {}, Event: {}]",
                    targetInstance.getClass().getSimpleName(),
                    targetMethod.getName(),
                    event, e);
        }
    }
}